﻿using TribesPSO;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TribesPSOTest.NUnit
{


    /// <summary>
    ///This is a test class for HyperspaceRandomTest and is intended
    ///to contain all HyperspaceRandomTest Unit Tests
    ///</summary>
    [TestFixture()]
    public class HyperspaceRandomTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///Tests that NextGaussianVector generates vectors that point in a random direction
        ///</summary>
        [Test()]
        public void NextGaussianVectorTest()
        {
            int samples = 500000;

            HyperspaceRandom target = new HyperspaceRandom(); // TODO: Initialize to an appropriate value
            EuclidianVector center = new EuclidianVector(0, 0);
            double sigma = 1F; // TODO: Initialize to an appropriate value

            List<double> angles = new List<double>();
            for (int n = 0; n < samples; n++)
            {
                EuclidianVector vector = target.NextGaussianVector(center, sigma);
                double angle = Math.Atan(vector[1] / vector[0]);
                angles.Add(angle);
            }

            for (double n = -Math.PI / 2 + Math.PI / 100; n <= Math.PI / 2; n += Math.PI / 100)
            {
                double hits = angles.Count(o => (o >= (n - Math.PI / 100)) && (o <= (n + Math.PI / 100)));
                double GeneratedPDF = hits / samples;
                Assert.AreEqual(.02, GeneratedPDF, .005, "Try running the test again because there's a bit of probability involved");
            }
        }

        /// <summary>
        ///A test for NextUniformVector that makes sure it always generates vectors with uniformly distributed lengths
        ///</summary>
        ///<remarks>Because this relies on probability, it can occasionally fail.  It's pretty uncommon though</remarks>
        [Test()]
        public void NextUniformVectorTest()
        {
            HyperspaceRandom target = new HyperspaceRandom();
            double radius = 1F;
            List<double> lengths = new List<double>();

            for (int dimensions = 1; dimensions <= 10; dimensions++)
            {
                EuclidianVector center = EuclidianVector.Origin(dimensions);
                for (int n = 0; n < 1000; n++)
                {
                    EuclidianVector actual = target.NextUniformVector(center, radius);
                    lengths.Add(actual.Length);
                }
            }

            for (double n = .05; n < 1; n += .05)
            {
                double hits = lengths.Count(o => (o >= (n - .05) && (o <= (n + .05))));
                double GeneratedPDF = hits / 10000;
                Assert.AreEqual(.1, GeneratedPDF, .01, "Try running the test again because there's a bit of probability involved");
            }
        }
    }
}
